/*
 * Written by edhong Mar. 2008
 *  main encoder/decoder routines for context-based arithmetic coding
 *   using modified QccPack arithmetic coder.
 * Feb 2008
 *
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 *
 */

#include "coder.h"
#include "SubbandIterator.h"
#include <limits.h>

int encode_subband_component(SubbandComponent *scarr, int numComponents, 
			     QccENTArithmeticModel *model, 
			     QccBitBuffer *output_buffer, 
			     contexttree* ct, 
			     int numbitplanes, 
			     int numbits, 
			     int (*f)(const CoeffHeapNode *, 
				      const CoeffHeapNode *,
				      const QccENTArithmeticModel *), 
			     int debug) {

  int bitcount = 0;

  if (numbitplanes < 0) numbitplanes = 32; 
  else numbits = INT_MAX;

  SubbandIterator si;
  if (f == NULL)
    SubbandIterator_InitAlloc(&si, scarr, numComponents, NULL, NULL, NULL);
  else {
    SubbandIterator_InitAlloc(&si, scarr, numComponents, f,  ct, model);

  }
  //  printf("numbits: %d, bitplanes: %d\n", numbits, numbitplanes);
  // iterate through coefficients, encoding them as appropriate
  sbploc sl; 
  sl = SubbandIterator_curr(&si);
  while (sl.k < numbitplanes) {
    int contextnum; 
    int nextbit;

    // set context. 
    contextnum = find_context_num(scarr,sl.comp,sl.i,sl.j,sl.subband,sl.k, ct);
    
    if  ((bitcount%100000 < 5))//|| (bitcount>1574900 && bitcount%1==0))
      ;//      printf(" %d %d %d %d %d %d:\n", bitcount, contextnum, sl.subband, sl.i, sl.j, sl.k);

    if ( QccENTArithmeticSetModelContext(model, contextnum)) {
      QccErrorAddMessage("encode_subband_component: error calling QccENTArithmeticSetModelContext");
      QccErrorExit();
    }

    if (bitcount==1574923){//sl.subband == 10 && sl.i==46 && sl.j == 32 && sl.k == 6) {
      //      printf("encode Stop here\n");
    }
    
    // encode value of bit
    nextbit = bit_value(&scarr[sl.comp].sub[sl.subband], sl.i, sl.j, sl.k );	  
    if (nextbit) update_descendant_siglevels(&scarr[sl.comp],sl.subband, sl.i, sl.j);
    if (QccENTArithmeticEncode(&nextbit, 
			       1, // BLOCK_LENGTH 
			       model, 
			       output_buffer)) {
      QccErrorAddMessage("encode_subband_component: error calling QccENTArithmeticEncode");
      QccErrorExit();
    }
    if (debug)
      printf("%d, %d %d %d %d %d:\n", nextbit, contextnum, sl.subband, sl.i, sl.j, sl.k);
    bitcount++;
    //	    printf("%d",nextbit);
    
    // if the coeff just became significant, also encode the sign
    if (scarr[sl.comp].sub[sl.subband].coeff[sl.i][sl.j].significance_level == sl.k) {
      // set context for sign bit
      contextnum = find_context_num(scarr,sl.comp,sl.i,sl.j,sl.subband,-1, ct);
      
      if ( QccENTArithmeticSetModelContext(model, contextnum)) {
	QccErrorAddMessage("encode_subband_component: error calling QccENTArithmeticSetModelContext");
	QccErrorExit();
      }
      
      // encode sign bit
      nextbit = bit_value(&scarr[sl.comp].sub[sl.subband], sl.i, sl.j, -1 );	  
      if (QccENTArithmeticEncode(&nextbit, 
				 1, // BLOCK_LENGTH 
				 model, 
				 output_buffer)) {
	QccErrorAddMessage("encode_subband_component: error calling QccENTArithmeticEncode");
	QccErrorExit();
      }
      if ((debug))// && (bitcount < 10000) )
	printf("%d, %d %d %d %d %d:\n", nextbit, contextnum, sl.subband, sl.i, sl.j, -1);
      bitcount++;
      //	    printf("%d",nextbit+2);    
    }
    if (bitcount >= numbits) return 0;
    
    SubbandIterator_updateAdvance(&si);
    sl = SubbandIterator_curr(&si);
  } // end sl.k < numbitplane;
  SubbandIterator_free(&si);
  return 0;
}


static SubbandComponent *sc1 = NULL;
static int numComponents1 = 0; 
static QccENTArithmeticModel *model1; 
static  QccBitBuffer *input_buffer1; 
static contexttree* ct1; 
static int numbitplanes1; 
static int numbits1; 
static int *bitcounter; 

static SubbandIterator subit; 
static int found_eof;

sbploc get_currentloc(void) {
  return SubbandIterator_curr(&subit) ;
}

// initialize decoder, setting decoding limits. 
// does not decode any bits... 
//  return result is error condition; 0 on success.  
// bitcounter is always set to the number of bits decoded
// sofar. 
void decode_subband_component_start(SubbandComponent *sc, int numComponents, 
				   QccENTArithmeticModel *model, 
				   QccBitBuffer *input_buffer, 
				   contexttree* ct, 
			     int (*f)(const CoeffHeapNode *, 
				      const CoeffHeapNode *,
				      const QccENTArithmeticModel *), 
				   int numbitplanes, 
				   int numbits, 
				    int *bitp, 
				   int debug) {
  sc1 = sc;
  numComponents1 = numComponents; 
  model1 = model;
  input_buffer1 = input_buffer;
  ct1 = ct;

  decode_subband_component_update_limit(
					numbitplanes, 
					numbits);

  bitcounter = bitp;
  *bitcounter = 0;
  if (f==NULL)
    SubbandIterator_InitAlloc(&subit,sc, numComponents, NULL, NULL, NULL );
  else
    SubbandIterator_InitAlloc(&subit,sc, numComponents, f, ct, model); 

  found_eof = 0;
}

void decode_subband_component_update_limit(
				   int numbitplanes, 
				   int numbits) {
  
  if (numbitplanes > 0) {
    numbitplanes1 = numbitplanes;
    numbits1 = INT_MAX;    
  }
  else {
    numbitplanes1 = 32;
    if (numbits <=0) 
      numbits1 = INT_MAX;    
    else {
      numbits1 = numbits;
    }
  } 

}

// attempts to decode additionalbits bits, stopping
//   when additionalbits have been decoded
// returns -1 if an error in a subroutine call happened, 
// returns 0 on successful decode of additionalbits bits, 
// returns 1 if specified limit is reached (and we did not
//             successfully decode additionalbits bits) 
// returns 2 if input_buffer is empty  (and the
//             criteria for returning 0 and 1 are not satisfied). 
int decode_subband_component_continue(int additionalbits, 
				      int debug) {
  if (additionalbits <=0) 
    additionalbits = INT_MAX;
  if (debug) printf("numbits %d, bitplanes %d\n", numbits1, numbitplanes1);
  int localbitcount;
  localbitcount = 0;
  int NumSubbands;
  int done = 0;
  int returnval = 0;

  NumSubbands= sc1[0].numSubbands;  

  if (found_eof) return 2;
  // iterate through coefficients, encoding them as appropriate
  sbploc sl = SubbandIterator_curr(&subit);
  while (sl.k < 33) {
    int contextnum; 
    int nextbit;
    int errorvalue;
    
    if (*bitcounter >= numbits1 || (sl.k == numbitplanes1)) {
      returnval =  1;
      done = 1;
    }
    if (done) goto finish;


    // set context. 
    contextnum = find_context_num(sc1,sl.comp,sl.i,sl.j,sl.subband,sl.k, ct1);

    if ((localbitcount%100000 < 5))//||(localbitcount>1574900 && localbitcount%1==0))
      ;//      printf("%d %d %d %d %d %d: \n", localbitcount, contextnum,  sl.subband, sl.i, sl.j, sl.k );
    
    if (localbitcount==1574923) {//sl.subband == 10 && sl.i==46 && sl.j == 32 && sl.k == 6) {
      //      printf("decode Stop here\n");
    }

    if ( QccENTArithmeticSetModelContext(model1, contextnum)) {
      QccErrorAddMessage("decode_subband_component_continue: error calling QccENTArithmeticSetModelContext");
      return -1;
    }

    errorvalue = QccENTArithmeticDecode(input_buffer1, 
					model1, 
					&nextbit, 
					1); //BLOCK_LENGTH
	  
    /*	  if ((localbitcount%400000> 399950) || 
	  (localbitcount%400000 < 50))*/

    if (debug)// && (localbitcount < 10000) )
      printf("%d, %d %d %d %d %d %d: \n",nextbit,  contextnum, sl.subband, sl.i, sl.j, sl.k, sl.comp);
    
    if (errorvalue == 2) {
      found_eof = 1; 
      returnval =2;
      // unable to decode current symbol;
      // next undecoded symbol location is given by sl  
      goto finish;
    }
    else if (errorvalue == 1) {
      fprintf(stderr, "decode_subband_component_continue: Error decoding next symbol;  last symbol was %d\n", nextbit);	
      returnval = -1;
      goto finish; // next undecoded symbol location is given by sl
    }
    else {
      //	printf("%d", nextbit);
      localbitcount++;
      (*bitcounter)++;
      
      
      // if the coeff just became significant, also decode the sign
      if (set_bit_value(nextbit, &sc1[sl.comp], sl.subband,  sl.i, sl.j, sl.k ))	{
	
	// set context for sign bit
	contextnum = find_context_num(sc1,sl.comp,sl.i,sl.j,sl.subband,-1, ct1);
	if ( QccENTArithmeticSetModelContext(model1, contextnum)) {
	  QccErrorAddMessage("decode_subband_component_continue: error calling QccENTArithmeticSetModelContext");
	  return -1;
	}
	
	// decode sign bit
	errorvalue = QccENTArithmeticDecode(input_buffer1, 
					    model1, 
					    &nextbit, 
					    1); // BLOCK_LENGTH 
	
	if (debug ) //&& (localbitcount < 10000) )
	  printf("%d, %d %d %d %d %d: \n",nextbit,  contextnum, sl.subband, sl.i, sl.j, -1);
	
	if (errorvalue == 2) {
	  //could not determine sign of coefficient; set its value back to 0. 
	  set_bit_value(0, &sc1[sl.comp], sl.subband, sl.i, sl.j, sl.k );
	  found_eof = 1; 
	  returnval = 2;
	  done = 1;
	}
	else if (errorvalue == 1) {
	  printf("decode_subband_component_continue: Error decoding sign symbol;  last symbol was %d\n", nextbit);	
	  returnval = -1;
	  goto finish;
	}
	else { // set sign symbol
	  set_bit_value(nextbit, &sc1[sl.comp], sl.subband, sl.i, sl.j, -1 );	
	  localbitcount++;
	  (*bitcounter)++;
	}
	
      }
      
      if (localbitcount >= additionalbits) {
	returnval= 0;
	done = 1;
	// go through loop again to make subit point to next bit location. 
      }
    }
    SubbandIterator_updateAdvance(&subit);
    sl = SubbandIterator_curr(&subit);
  }
  if (localbitcount >= additionalbits)
    returnval= 0;
  else
    returnval= 1;

 finish:
  return returnval;

}
